import { NitroConfig } from '../../config/NitroConfig.js'
import { getForwardDeclaration } from '../../syntax/c++/getForwardDeclaration.js'
import { includeHeader } from '../../syntax/c++/includeNitroHeader.js'
import { getAllKnownTypes } from '../../syntax/createType.js'
import { getHybridObjectName } from '../../syntax/getHybridObjectName.js'
import {
  createFileMetadataString,
  isNotDuplicate,
} from '../../syntax/helpers.js'
import type { SourceFile } from '../../syntax/SourceFile.js'
import { getTypeAs } from '../../syntax/types/getTypeAs.js'
import { HybridObjectType } from '../../syntax/types/HybridObjectType.js'

export function getUmbrellaHeaderName(): string {
  const moduleName = NitroConfig.current.getIosModuleName()
  return `${moduleName}-Swift-Cxx-Umbrella.hpp`
}

export function createSwiftUmbrellaHeader(): SourceFile {
  const moduleName = NitroConfig.current.getIosModuleName()
  const filename = getUmbrellaHeaderName()

  const types = getAllKnownTypes('swift')

  const swiftForwardDeclares = types
    .filter((t) => t.kind === 'hybrid-object')
    .map((t) => {
      const hybridObjectType = getTypeAs(t, HybridObjectType)
      const hybridObjectModuleName =
        hybridObjectType.sourceConfig.getIosModuleName()
      const name = getHybridObjectName(hybridObjectType.hybridObjectName)
      return getForwardDeclaration(
        'class',
        name.HybridTSpecCxx,
        hybridObjectModuleName
      )
    })
    .filter(isNotDuplicate)

  const imports = types.flatMap((t) => t.getRequiredImports('c++'))
  const forwardDeclarations = imports
    .map((i) => i.forwardDeclaration)
    .filter((f) => f != null)
    .filter(isNotDuplicate)
  const includes = imports.map((i) => includeHeader(i)).filter(isNotDuplicate)

  const code = `
${createFileMetadataString(filename, '///')}

#pragma once

// Forward declarations of C++ defined types
${forwardDeclarations.sort().join('\n')}

// Include C++ defined types
${includes.sort().join('\n')}

// C++ helpers for Swift
#include "${moduleName}-Swift-Cxx-Bridge.hpp"

// Common C++ types used in Swift
#include <NitroModules/ArrayBufferHolder.hpp>
#include <NitroModules/AnyMapUtils.hpp>
#include <NitroModules/RuntimeError.hpp>
#include <NitroModules/DateToChronoDate.hpp>

// Forward declarations of Swift defined types
${swiftForwardDeclares.sort().join('\n')}

// Include Swift defined types
#if __has_include("${moduleName}-Swift.h")
// This header is generated by Xcode/Swift on every app build.
// If it cannot be found, make sure the Swift module's name (= podspec name) is actually "${moduleName}".
#include "${moduleName}-Swift.h"
// Same as above, but used when building with frameworks (\`use_frameworks\`)
#elif __has_include(<${moduleName}/${moduleName}-Swift.h>)
#include <${moduleName}/${moduleName}-Swift.h>
#else
#error ${moduleName}'s autogenerated Swift header cannot be found! Make sure the Swift module's name (= podspec name) is actually "${moduleName}", and try building the app first.
#endif
`

  return {
    content: code,
    language: 'c++',
    name: filename,
    platform: 'ios',
    subdirectory: [],
  }
}
